package com.cabal.common.aliyunOSS;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.cabal.common.config.AliyunOSSConfig;
import com.cabal.common.errcode.CommonErrorCodeEnum;
import com.cabal.common.errcode.ErrorCodeEnum;
import com.cabal.common.util.TmsServiceException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * AliyunOSS 工具类
 *
 * @author shenkang
 * @data 2022年4月28日
 */
public class AliyunOSSUtil {

    private static Logger logger = LoggerFactory.getLogger(AliyunOSSUtil.class);

    private static String FILE_URL;
    private static String bucketName = AliyunOSSConfig.ALIYUN_OSS_BUCKETNAME;
    private static String endpoint = AliyunOSSConfig.ALIYUN_OSS_ENDPOINT;
    private static String accessKeyId = AliyunOSSConfig.ALIYUN_OSS_KEYID;
    private static String accessKeySecret = AliyunOSSConfig.ALIYUN_OSS_KEYSECRET;
    private static String fileHost = AliyunOSSConfig.ALIYUN_OSS_FILEHOST;
    private static String rootPath = AliyunOSSConfig.ALIYUN_OSS_ROOT_PATH;


    /**
     * 上传文件。
     *
     * @param file 需要上传的文件路径
     * @return 如果上传的文件是图片的话，会返回图片的"URL"，如果非图片的话会返回"非图片，不可预览。文件路径为：+文件路径"
     */
    public static String upLoadLicense(File file, String rout, String fileName) {
        // 判断文件
        if (file == null) {
            return null;
        }
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 设置文件路径和名称
            String fileUrl = rout + "/" + fileName;
            // 上传文件
            PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, rout + "/" + fileName, file));
            // 设置权限(公开读)
            //ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private);
            if (result != null) {
                logger.info("------OSS文件上传成功------" + fileUrl);
            }
            return fileUrl;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
            if (file != null) {
                file.delete();
            }
        }
    }

    /**
     * @Description: 根据⽂件路径获取InputStream流
     */
    public static InputStream getInputStreamByFileUrl(String ossPath,String ossUrl) {
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        String fileName = ossPath;
        //判断文件是否存在
        boolean found = ossClient.doesObjectExist(bucketName, fileName);
        //先去待申报文件夹找，找不到就去已申报文件夹找
        if (!found){
            logger.info("文件不存在"+",文件地址："+fileName);
            fileName = ossUrl;
            found = ossClient.doesObjectExist(bucketName, fileName);
            if (!found){
                logger.info("文件不存在"+",文件地址："+fileName);
                throw new TmsServiceException(ErrorCodeEnum.PARAM_ERROR,"找不到原始报文");
            }

        }
        logger.info("文件地址："+fileName);
        // ossObject包含⽂件所在的存储空间名称、⽂件名称、⽂件元信息以及⼀个输⼊流。
        OSSObject ossObject = ossClient.getObject(bucketName, fileName);

        return ossObject.getObjectContent();
    }

    /**
     * 获取图片访问路径
     *
     * @param url
     * @return
     */
    public static String findimg(String url, Long time) {
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + time);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL urla = ossClient.generatePresignedUrl(bucketName, url, expiration);
        return urla.toString();
    }


    /**
     * 获取图片访问路径
     *
     * @param url
     * @return
     */
    public static String findimg(String url) {
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL urla = ossClient.generatePresignedUrl(bucketName, url, expiration);
        return urla.toString();
    }

    /**
     * 上传文件。
     *
     * @param file 需要上传的文件路径
     * @return 如果上传的文件是图片的话，会返回图片的"URL"，如果非图片的话会返回"非图片，不可预览。文件路径为：+文件路径"
     */
    public static String upLoad(File file, String logisticsPagImg, String fileName) {
        // 默认值为：true
        boolean isImage = true;
        // 判断所要上传的图片是否是图片，图片可以预览，其他文件不提供通过URL预览
        try {
            Image image = ImageIO.read(file);
            isImage = image == null ? false : true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        String fileUrl="";
        logger.info("------OSS文件上传开始--------" + fileName);

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = format.format(new Date());

        // 判断文件
        if (file == null) {
            return null;
        }
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 判断容器是否存在,不存在就创建
            if (!ossClient.doesBucketExist(bucketName)) {
                ossClient.createBucket(bucketName);
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                createBucketRequest.setCannedACL(CannedAccessControlList.Private);
                ossClient.createBucket(createBucketRequest);
            }
            // 设置文件路径和名称
            fileUrl = fileHost + "/" + logisticsPagImg + "/" + fileName;
            if (isImage) {//如果是图片，则图片的URL为：....
                FILE_URL = fileName;
            } else {
                FILE_URL = "非图片，不可预览。文件路径为：" + fileUrl;
            }

            // 上传文件
            PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, fileName, file));
            // 设置权限(公开读)
//            ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
            if (result != null) {
                logger.info("------OSS文件上传成功------" + fileUrl);
            }
        } catch (OSSException oe) {
            logger.error(oe.getMessage());
        } catch (ClientException ce) {
            logger.error(ce.getErrorMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return fileUrl;
    }


    /**
     * 上传文件。
     *
     * @param file 需要上传的文件路径
     * @return 直接返回文件路径
     */
    public static String upLoadFile(File file, String subDir, String fileName) {
        logger.info("------OSS文件上传开始--------" + fileName);

        // 判断文件
        if (file == null) {
            return null;
        }

        String filePath = subDir + fileName;

        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 判断容器是否存在,不存在就创建
            if (!ossClient.doesBucketExist(bucketName)) {
                ossClient.createBucket(bucketName);
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                createBucketRequest.setCannedACL(CannedAccessControlList.Private);
                ossClient.createBucket(createBucketRequest);
            }

            // 上传文件
            PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, filePath, file));
            // 设置权限(公开读)
            //ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private);
            if (result != null) {
                logger.info("------OSS文件上传成功------" + filePath);
            }
        } catch (OSSException oe) {
            logger.error(oe.getMessage());
        } catch (ClientException ce) {
            logger.error(ce.getErrorMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return filePath;
    }

    /**
     * 查询文件是否存在
     *
     * @param fileName
     * @return
     */
    public static boolean findFile(String fileName) {

        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        boolean found = false;
        try {
            found = ossClient.doesObjectExist(bucketName, fileName);
        } catch (OSSException oe) {
            logger.error(oe.getMessage());
        } catch (ClientException ce) {
            logger.error(ce.getErrorMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return found;
    }

    public static Boolean upLoadOss(File file, String folder, String fileName) {
        // 默认值为：true
        boolean isImage = true;
        // 判断所要上传的图片是否是图片，图片可以预览，其他文件不提供通过URL预览
        try {
            Image image = ImageIO.read(file);
            isImage = image != null;
        } catch (IOException e) {
            e.printStackTrace();
        }

        logger.info("------OSS文件上传开始--------" + fileName);
        // 判断文件
        if (file == null) {
            return false;
        }
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        try {
            // 判断容器是否存在,不存在就创建
            if (!ossClient.doesBucketExist(bucketName)) {
                ossClient.createBucket(bucketName);
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                createBucketRequest.setCannedACL(CannedAccessControlList.Private);
                ossClient.createBucket(createBucketRequest);
            }
            // 设置文件路径和名称
            String fileUrl = fileHost + "/" + folder + "/" + fileName;
            if (isImage) {//如果是图片，则图片的URL为：....
                FILE_URL = "https://" + bucketName + "." + endpoint + "/" + fileUrl;
            } else {
                FILE_URL = "非图片，不可预览。文件路径为：" + fileUrl;
            }

            // 上传文件
            PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, folder + "/" + fileName, file));
            // 设置权限(公开读)
            //ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private);
            if (result != null) {
                logger.info("------OSS文件上传成功------" + fileUrl);
                return true;
            }
        } catch (OSSException oe) {
            logger.error(oe.getMessage());
        } catch (ClientException ce) {
            logger.error(ce.getErrorMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return false;
    }


    /**
     * 通过文件名下载文件
     *
     * @param objectName 要下载的文件名
     */
    public static String downloadFile(HttpServletResponse response, String objectName) throws Exception {

        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        boolean found = ossClient.doesObjectExist(bucketName, objectName.concat(".zip"));
        if (!found) {
            throw new TmsServiceException(CommonErrorCodeEnum.FAIL, "文件不存在，请检查运单号是否正确!");
        }
        Date expiration = new Date(new Date().getTime() + 3600 * 10000);
        String url = ossClient.generatePresignedUrl(bucketName, objectName.concat(".zip"), expiration).toString();
        return url;

    }


    /**
     * byte方式上传
     *
     * @param fileName
     * @param bytes
     * @return
     */
    public static String uploadByByte(String fileName, byte[] bytes) {
        try {
            String ossKey = String.format("%s%s", rootPath, fileName);
            OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            oss.putObject(bucketName, ossKey, new ByteArrayInputStream(bytes));
            oss.shutdown();

            return ossKey;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * byte方式上传
     *
     * @param fileName
     * @param bytes
     * @return
     */
    public static String uploadByByte2(String fileName, byte[] bytes) {
        try {
            OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            oss.putObject(bucketName, fileName, new ByteArrayInputStream(bytes));
            oss.shutdown();

            return fileName;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    public static File downFile(String fileName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        File tempFile = null;
        try {
            GetObjectRequest object = new GetObjectRequest(bucketName, fileName);
            tempFile = File.createTempFile(String.valueOf(System.currentTimeMillis()), ".jpg");
            ossClient.getObject(object, tempFile);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            ossClient.shutdown();
        }
        return tempFile;
    }

    public static void downFile(String key, File file) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            GetObjectRequest object = new GetObjectRequest(bucketName, key);
            ossClient.getObject(object, file);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * Base64方式上传
     *
     * @param imageUri
     * @param ossKey
     * @return
     */
    public static String uploadByBase64(String imageUri, String ossKey) {
        if (StringUtils.isBlank(imageUri)) {
            return null;
        }
        if (imageUri.contains(";base64")) {
            imageUri = imageUri.substring(imageUri.lastIndexOf(",") + 1);
        }
        byte[] imgByte = Base64Utils.decodeFromString(imageUri);
        try {
            ossKey = uploadByByte(ossKey, imgByte);
        } catch (Exception e) {
            logger.error("文件上传失败：" + e.getMessage(), e);
            return null;
        }
        return ossKey;
    }


    /**
     * @param fileName
     * @param file
     * @return ossPath     与crfp 路径一致
     */
    public static String uploadByFile(String fileName, File file) {
        String ossKey = String.format("%s%s", rootPath, fileName);
        OSS oss = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        oss.putObject(bucketName, ossKey, file);
        oss.shutdown();
        return ossKey;
    }


    /**
     * 通过文件流上传文件。
     *
     * @param inputStream 上传流，上传完毕后默认关闭
     * @return 上传成功返回文件路径
     * @author zhaojq<jovenkingzhao @ jieztech.com>
     */
    public static String uploadByInputStream(InputStream inputStream, String subDir, String fileName) throws Exception {
        logger.info("------OSS文件上传开始--------" + fileName);

        String filePath = subDir + fileName;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 判断容器是否存在,不存在就创建
            if (!ossClient.doesBucketExist(bucketName)) {
                ossClient.createBucket(bucketName);
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                createBucketRequest.setCannedACL(CannedAccessControlList.Private);
                ossClient.createBucket(createBucketRequest);
            }
            // 上传文件
            PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, filePath, inputStream));
            if (result != null) {
                logger.info("------OSS文件上传成功------" + filePath);
                return filePath;
            }
        } catch (Exception e) {
            logger.error("文件上传异常", e);
            throw e;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                logger.error("文件上传异常", e);
                throw e;
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
            }
        }
        return null;
    }

    public static File downTemplateFile(String fileName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        File tempFile = null;
        try {
            GetObjectRequest object = new GetObjectRequest(bucketName, fileName);
            tempFile = File.createTempFile(UUID.randomUUID().toString(), null);
            ossClient.getObject(object, tempFile);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            ossClient.shutdown();
        }
        return tempFile;
    }

    /**
     * 获取OSS目录下所有文件
     *
     * @author zhaojq<jovenkingzhao @ jieztech.com>
     * @date 2022-05-05 12:05
     */
    public static List<OSSObjectSummary> listObjects(String ossPath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
            listObjectsRequest.setBucketName(bucketName);
            listObjectsRequest.setPrefix(ossPath);
            listObjectsRequest.setMaxKeys(1000);
            // 列举文件。如果不设置keyPrefix，则列举存储空间下的所有文件。如果设置keyPrefix，则列举包含指定前缀的文件。
            ObjectListing objectListing = ossClient.listObjects(listObjectsRequest);
            return objectListing.getObjectSummaries();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            ossClient.shutdown();
        }
        return new ArrayList<>();
    }

    /**
     * 文件移动
     *
     * @author zhaojq<jovenkingzhao @ jieztech.com>
     * @date 2022-05-05 15:18
     */
    public static boolean moveFile(String sourcePath, String destPath) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucketName, sourcePath, bucketName, destPath);
            // 复制文件。
            ossClient.copyObject(copyObjectRequest);
            //删除源文件
            ossClient.deleteObject(bucketName, sourcePath);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            ossClient.shutdown();
        }
        return false;
    }
}
